package org.grow.ceto.controller;

import org.grow.ceto.entity.CombineDto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Author: xwg
 * @CreateDate: 2021/10/12
 */

@RestController
public class CombineController {
    Logger logger = LoggerFactory.getLogger(CombineController.class);


    @Value("${target:/home/xieweig/document/front}")
    private String from;
    @Value("${dest:/home/xieweig/document/front/dest}")
    private String dest = "/home/xieweig/document/front/dest";

    //    private List<String> fileKeys= Arrays.asList("03","04","05","06");
    @Value("${fileKeys}")
    private List<String> fileKeys = Arrays.asList("03", "04");


    @PostMapping("/combineFile")
    public Integer totalCombine(@RequestBody CombineDto combineDto) throws IOException {
        String destDir = combineDto.getDestDir();
        List<String> subDirs = combineDto.getSubDirs();
        String fromDir = combineDto.getFromDir();
        System.out.println(combineDto);
        if (StringUtils.hasText(fromDir)) {
//            线程不安全 如何处理
            this.from = fromDir;
        }
        if (StringUtils.hasText(destDir)) {
            this.dest = destDir;
        }
        if (!CollectionUtils.isEmpty(subDirs)) {
            fileKeys = subDirs;
        }
//       第一步 校验对手是否存在
        List<Path> paths = this.dirValidate(from);
//       第二步 纠正对手基本信息
        List<Path> pathsM = this.exactlyDir(from, paths);
//        第三步 打败对手
        Integer integer = this.moveCore(pathsM);
        return integer;
    }

    //第一步校验目录
    public List<Path> dirValidate(String fromDir) throws IOException {
        logger.info("要合并文件的path");
        Path target = Paths.get(fromDir);
        Assert.isTrue(Files.exists(target), "目标文件目录不存在");
//        校验文件名准确性
        logger.info("开始校验一级总目录: ");
        Stream<Path> groups = Files.list(target);

        List<Path> passed = groups.filter(Files::isDirectory)
                .filter(p -> Pattern.matches("^\\d{1,2}组$", p.getFileName().toString()))
                .collect(Collectors.toList());
        logger.info("初始校验通过的目录：" + passed);
        /**
         * 初始校验通过的目录：[/home/xieweig/document/front/2组,
         * /home/xieweig/document/front/8组,
         * /home/xieweig/document/front/16组,
         *  /home/xieweig/document/front/11组]
         *
         * */
        return passed;
    }

    //第二步纠正目录 只能纠正一级 因为压缩解压
// 会出现 /home/xieweig/document/front/11组]
//    /home/xieweig/document/front/11组/11组
//    这种目录结构 ，只纠正一级，
    public List<Path> exactlyDir(String fromDir, List<Path> paths) {
        List<Path> r = paths.stream().map(p -> {
                    String s = p.getFileName().toString();
                    Path output = p;
//            s 11组
                    Stream<Path> list = null;
                    try {
                        list = Files.list(p);

                    } catch (IOException e) {
                        logger.error("文件目录下无内容" + p);
                    }
                    List<Path> collect = list.filter(x -> x.getFileName().toString().contains(s))
                            .collect(Collectors.toList());
                    long count = collect.size();
                    if (count == 0) {
                        logger.debug("不需要纠正目录：" + p);
                    } else {
                        logger.debug("需要纠正目录：" + count + " => " + collect);
                        if (count == 1) {
                            Path path = collect.get(0);
                            output = path;
                        }
                    }
                    return output;

                }
        ).collect(Collectors.toList());
        logger.info("纠正完毕后的目录：" + r);
        /**
         * 纠正完毕后的目录：[/home/xieweig/document/front/2组/2组,
         * /home/xieweig/document/front/8组/8组,
         * /home/xieweig/document/front/16组,
         * /home/xieweig/document/front/11组/11组]
         * */
        return r;

    }

    public Integer moveCore(List<Path> paths) throws IOException {
        System.out.println(paths);
        System.out.println(dest);
        List<Path> fileExits = new ArrayList<>();
        Path destination = Paths.get(dest);
        Pattern fileReg = Pattern.compile(".*\\d+.*");
        for (String fileKey : fileKeys) {
            logger.debug("开始解决fileKey: " + fileKey);
//          实例：  开始解决  ：02
            for (Path path : paths) {
                Stream<Path> list = Files.list(path);
                List<Path> r = list.filter(x -> x.getFileName().toString().contains(fileKey)).collect(Collectors.toList());
                if (r.size() == 1) {
                    Path t = r.get(0);
                    logger.debug("解决" + fileKey + "中" + t + "正确找到目标");
//                    解决03中/home/xieweig/document/front/2组/2组/提交03：课程实训_项目开发日志_学生正确找到目标
//                    移动开始

                    Path finalDestDir = destination.resolve(t.getFileName());
                    System.out.println("归档目录" + finalDestDir);
                    Stream<Path> contents = Files.list(t);
                    contents
                            //                    过滤掉文件夹子
                            .filter(Files::isRegularFile)
                            //                    过滤文件名中有~$符号的，一般是示例或备份文件
                            .filter(x -> !x.getFileName().toString().contains("~$"))
//                            过滤出文件中名字包含数字 也就是小组编号的
//                            .filter(x -> x.getFileName().toString().matches(".*\\d+.*"))
                            .filter(x -> fileReg.matcher(x.getFileName().toString()).matches())
                            .forEach(x -> {

                                Path fileName = x.getFileName();
//                        归档的最后的位置
                                Path resolve = finalDestDir.resolve(fileName);
                                String s = ("移动开始了 源文件：" + x + " 。目标文件：" + resolve);
                                System.out.println(s);
                                try {
                                    Files.copy(x, resolve);
                                } catch (IOException e) {
                                    fileExits.add(x);
                                }

                            });


                } else {
                    logger.warn("没有正确解决" + path);
                }

            }
        }
        logger.info("由于目标同名文件已经存在，导致如下文件没有被移动，在安全模式下，请手动移动 : " + fileExits);
        return fileExits.size();

    }


}
